#include <hardware.h>
#include <delay.h>
#include <viniSPI.h>
#include <sim.h>
#include <nmea.h>
//extern unsigned char write_stat;
//extern unsigned char write_stat_fe;
//extern unsigned char write_stat_pe;
//extern unsigned char write_stat_do;

gpgga_struct gpgga_msg;
gprmc_struct gprmc_msg;

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

void gps_putstr(char *str)
{
char k;
while (k = *str++)
    {
    gps_putchar(k);
    }
}

void gps_putstrf(char flash *str)
{
char k;
while (k = *str++)
    {
    gps_putchar(k);
    }
}

void sim_putstr(char *str)
{
char k;
while (k = *str++)
    {
    sim_putchar(k);
    }
}

void sim_putstrf(char flash *str)
{
char k;
while (k = *str++)
    {
    sim_putchar(k);
    }
}

// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 128
char rx_buffer0[RX_BUFFER_SIZE0];

#if RX_BUFFER_SIZE0<256
unsigned char rx_wr_index0, rx_rd_index0, rx_counter0;
#else
unsigned int rx_wr_index0, rx_rd_index0, rx_counter0;
#endif

// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;

// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
char status, data;
status = UCSR0A;
data = UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0)
    {
    if (data == GPS_END_OF_FIELD) // comma
        {
        rx_buffer0[rx_wr_index0] = BUFFER_END_OF_FIELD;
        }
        
    else if (data == BUFFER_END_OF_FIELD)
        {
        rx_buffer0[rx_wr_index0] = 0;
        }
        
    else
        {
        rx_buffer0[rx_wr_index0] = data;
        }
        
//    char2buffer(data); // MOVE TO gps_getchar
            
    if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0 = 0;
    if (++rx_counter0 == RX_BUFFER_SIZE0)
        {
        rx_counter0 = 0;
        rx_buffer_overflow0 = 1;
        }

    if (data == BUFFER_END_OF_FIELD)
        {
        nmea_read(&gpgga_msg, &gprmc_msg, 1);
        }
    }

else
    {
    UCSR0A=0x00;
    char2buffer('E');
    char2buffer(status & 0x30);
//    write_stat_pe = write_stat_pe + ((status & PARITY_ERROR) == PARITY_ERROR);
//    write_stat_fe = write_stat_fe + ((status & FRAMING_ERROR) == FRAMING_ERROR);
//    write_stat_do = write_stat_do + ((status & DATA_OVERRUN) == DATA_OVERRUN);
    }
}

// USART1 Receiver buffer
#define RX_BUFFER_SIZE1 128
char rx_buffer1[RX_BUFFER_SIZE1];

#if RX_BUFFER_SIZE1<256
unsigned char rx_wr_index1, rx_rd_index1, rx_counter1;
#else
unsigned int rx_wr_index1, rx_rd_index1, rx_counter1;
#endif

// This flag is set on USART1 Receiver buffer overflow
bit rx_buffer_overflow1;

// USART1 Receiver interrupt service routine
interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status, data;
status = UCSR1A;
data = UDR1;

if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0)
    {
    if (data == BUFFER_END_OF_FIELD)
        {
        rx_buffer1[rx_wr_index1] = 0;
        }
        
    else
        {
        rx_buffer1[rx_wr_index1] = data;
        }
        
    char2buffer(data); // MOVE TO SIM_GETCHAR
    
            
    if (++rx_wr_index1 == RX_BUFFER_SIZE1) rx_wr_index1 = 0;
    if (++rx_counter1 == RX_BUFFER_SIZE1)
        {
        rx_counter1 = 0;
        rx_buffer_overflow1 = 1;
        }
    
    if (data == BUFFER_END_OF_FIELD) sim_interpret_message();

    }
    

else
    {
    UCSR1A=0x00;
    char2buffer('E');
    char2buffer(status & 0x30);
//    write_stat_pe = write_stat_pe + ((status & PARITY_ERROR) == PARITY_ERROR);
//    write_stat_fe = write_stat_fe + ((status & FRAMING_ERROR) == FRAMING_ERROR);
//    write_stat_do = write_stat_do + ((status & DATA_OVERRUN) == DATA_OVERRUN);
    }
}

//#ifndef _DEBUG_TERMINAL_IO_
//#define _ALTERNATE_GETCHAR_
// Get a character from the USART0 Receiver buffer
#pragma used+
char gps_getchar(void)
{
char data;
while (rx_counter0 == 0); // NO TIMEOUT!
data = rx_buffer0[rx_rd_index0];
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0 = 0;

#asm("cli")
--rx_counter0;
#asm("sei")

return data;
}
#pragma used-
//#endif

//#ifndef _DEBUG_TERMINAL_IO_
//#define _ALTERNATE_GETCHAR_
// Get a character from the USART0 Receiver buffer
#pragma used+
char sim_getchar(void)
{
char data;
while (rx_counter1 == 0); // NO TIMEOUT!
data = rx_buffer1[rx_rd_index1];
if (++rx_rd_index1 == RX_BUFFER_SIZE1) rx_rd_index1 = 0;

#asm("cli")
--rx_counter1;
#asm("sei")

return data;
}
#pragma used-
//#endif

char gps_getchar_timed(unsigned int *timeout_100us)
{
char data;
while ((rx_counter0 == 0) && (*timeout_100us > 0))
    {
//    #asm("cli")
    delay_us(100);
//    #asm("sei")

    (*timeout_100us)--;
    }

if (*timeout_100us > 0)
    {    
    data = rx_buffer0[rx_rd_index0];
    if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0 = 0;

    #asm("cli")
    --rx_counter0;
    #asm("sei")
    }
    
else
    {
    data = -1;
    }
    
return data;
}

// USART0 Transmitter buffer
#define TX_BUFFER_SIZE0 8
char tx_buffer0[TX_BUFFER_SIZE0];

#if TX_BUFFER_SIZE0<256
unsigned char tx_wr_index0, tx_rd_index0, tx_counter0;
#else
unsigned int tx_wr_index0, tx_rd_index0, tx_counter0;
#endif

// USART0 Transmitter interrupt service routine
interrupt [USART0_TXC] void usart0_tx_isr(void)
{
if (tx_counter0)
    {
    --tx_counter0;
    UDR0 = tx_buffer0[tx_rd_index0];
    char2buffer(tx_buffer0[tx_rd_index0]);
    if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0 = 0;
    }
}

// USART1 Transmitter buffer
#define TX_BUFFER_SIZE1 8
char tx_buffer1[TX_BUFFER_SIZE1];

#if TX_BUFFER_SIZE1<256
unsigned char tx_wr_index1, tx_rd_index1, tx_counter1;
#else
unsigned int tx_wr_index1, tx_rd_index1, tx_counter1;
#endif

// USART1 Transmitter interrupt service routine
interrupt [USART1_TXC] void usart1_tx_isr(void)
{
if (tx_counter1)
    {
    --tx_counter1;
    UDR1 = tx_buffer1[tx_rd_index1];
    char2buffer(tx_buffer1[tx_rd_index1]);
    if (++tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1 = 0;
    }
}

//#ifndef _DEBUG_TERMINAL_IO_
//#define _ALTERNATE_PUTCHAR_
// Write a character to the USART0 Transmitter buffer
#pragma used+
void gps_putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm("cli")
if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY) == 0))
    {
    tx_buffer0[tx_wr_index0] = c;
    if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0 = 0;
    ++tx_counter0;
    }

else
    {
    UDR0 = c;
    char2buffer(c);
    }
#asm("sei")
}
#pragma used-
//#endif

//#ifndef _DEBUG_TERMINAL_IO_
//#define _ALTERNATE_PUTCHAR_
// Write a character to the USART0 Transmitter buffer
#pragma used+
void sim_putchar(char c)
{
while (tx_counter1 == TX_BUFFER_SIZE1);
#asm("cli")
if (tx_counter1 || ((UCSR1A & DATA_REGISTER_EMPTY) == 0))
    {
    tx_buffer1[tx_wr_index1] = c;
    if (++tx_wr_index1 == TX_BUFFER_SIZE1) tx_wr_index1 = 0;
    ++tx_counter1;
    }

else
    {
    UDR1 = c;
    char2buffer(c);
    }
#asm("sei")
}
#pragma used-
//#endif
  